
#include <string.h>
#include <stdlib.h>
#include "hashtable.h"
#include "garbage.h"

hash_table new_hash_table(int size, int multiplier) {
	hash_table t;
	t = (hash_table) new_garbage(1, sizeof(struct hash_table));
	t->size = (size ? size : 43);
	t->table = (hash_entry *) new_garbage(t->size, sizeof(hash_entry));
	t->multiplier = (multiplier ? multiplier : 37);

	return t;
}

hash_int hash(hash_table t, char * key) {
	hash_int h;
	unsigned char * p;

	h = 0;
	for (p = (unsigned char *) key; *p; p++)
		h = t->multiplier * h + *p;

	return h % t->size;
}

hash_entry hash_use(hash_table t, char * key, int create, void * value) {
	hash_int h;
	hash_entry s;

	h = hash(t, key);

	for(s = t->table[h]; s; s = s->next)
		if (strcmp(key, s->key) == 0)
			return s;
	if (create) {
		s = (hash_entry) new_garbage(1, sizeof(struct hash_entry));
		s->key = key;
		s->value = value;
		s->next = t->table[h];
		t->table[h] = s;
		t->count++;
	}

	return s;

}

void * hash_get(hash_table t, char * key) {
	hash_entry h;
	h = hash_use(t, key, 1, 0);
	return h->value;
}

void hash_set(hash_table t, char * key, void * value) {
	hash_entry h;
	h = hash_use(t, key, 1, 0);
	h->value = value;
}

char ** hash_keys(hash_table t) {
	hash_entry s;
	char ** keys;
	int i;
	int n = 0;

	keys = (char **) new_garbage(t->count, sizeof(char *));

	for (i = 0; i < t->size; ++i)
		for (s = t->table[i]; s; s = s->next)
			keys[n++] = s->key;

	return keys;
}

void ** hash_values(hash_table t) {
	hash_entry s;
	void ** values;
	int i;
	int n = 0;

	values = (void **) new_garbage(t->count, sizeof(void *));

	for (i = 0; i < t->size; ++i)
		for (s = t->table[i]; s; s = s->next)
			values[n++] = s->value;

	return values;
}

int hash_count(hash_table t) { return t->count; }
